<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>this,call,apply</title>
</head>

<body>
    <script>
        // 一般来说，this指向大致可以分为4种
        // 1、作为对象的方法调用。2、作为普通函数调用。3、构造器调用。4、call和apply调用

        // 1、当函数作为对象的方法被调用时，this指向该对象
        var obj = {
            a: 1,
            getA: function () {
                console.log(this === obj); // true
                console.log(this.a);//1
            }
        }

        obj.getA() // 函数作为对象的方法调用


        // 2、作为普通函数调用，this总是指向全局对象，在浏览器里，是window
        // window.name = 'globalName'
        // var getName = function () {
        //     return this.name
        // }
        // console.log(getName()); // globalName

        window.name = 'globalName1'
        var myObj = {
            name:'seven',
            getName:function(){
                return this.name
            }
        }
        var getName1 = myObj.getName
        console.log(getName1()); //globalName1，，获取到了对象的方法，但是是作为普通函数调用的（也就是不是通过obj.调用的）


        // 3、构造器调用：和普通函数没有什么区别，唯一区别在于调用的方式，当用new运算符调用函数时，该函数总会返回一个对象
        // 通常情况下，this就指向返回的这个对象
        var MyClass = function(){
            // 指向返回的对象，也就是这时的this == 后面创建的新对象obj，相当于obj.name = 'lhb'
            this.name = "lhb"
        }
        var obj = new MyClass()
        console.log(obj.name); //lhb

        // 注意：如果构造函数显示的返回一个Object类型的对象，那么此次运算结果会返回这个对象，而不是期待的this
        var youClass = function(){
            this.name = 'you';
            return{
                name:'pp'
            }
        }

        var youobj = new youClass()
        console.log(youobj.name);// pp ,因为返回的是一个{name:'pp'}


        //4、 call和apply调用 : 可以动态的改变传入函数的this
        var obj3 = {
            name:'obj3',
            getName:function(){
                return this.name
            }
        }
        var obj4 = {
            name:'obj4'
        }

        console.log(obj3.getName()); // obj3:函数作为对象的方法调用，this就是该对象，即obj3
        console.log(obj3.getName.call(obj4));// obj4：函数作为对象的方法调用，this指向对象。因为动态的改变了this，所以this指向对象obj4.


        // 注意点：当把对象的方法转换成普通函数调用是，容易出问题
        // 例如：
        var getId = document.getElementById
        getId("box") // 报错。因为getElementById内部实现需要用到this，本来是作为document的对象方法调用的，所以
        // 内部this是document，没错。而此时一转换，getId变成了普通函数调用，this变成了window，就没有getElementById方法了



    </script>
</body>

</html>